package cn.iocoder.yudao.module.bpm.service.amis;


import cn.hutool.core.io.IoUtil;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.module.bpm.api.amis.dto.AmisListColumConfigDto;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.CellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.ss.usermodel.*;
import org.springframework.stereotype.Service;
import org.ssssssss.script.functions.DateExtension;

import javax.annotation.Resource;
import java.io.ByteArrayOutputStream;
import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;

@Service
@Log4j2
public class AmisFormDataAnalysisImpl implements AmisFormDataAnalysis{

    @Resource
    private AmisFormConfigAnalysis amisFormConfigAnalysis;

    @Override
    public byte[] amisExportToExcel(String amisFormCode, String type, List<Map> dataList) {
        List<AmisListColumConfigDto> amisListColumConfigDtoList = amisFormConfigAnalysis.analysisColumnList(amisFormCode, type);

        // 处理表头
        Map<String, AmisListColumConfigDto> stringAmisListColumConfigDtoMap = new LinkedHashMap<>();

        // 表头
        ArrayList head = new ArrayList();
        {

            amisListColumConfigDtoList.stream()
                    .filter((data) -> {
                        return data.getVisible() == null || data.getVisible() != false;
                    })
                    .forEach((data) -> {

                        stringAmisListColumConfigDtoMap.put(data.getName(), data);
                        ArrayList headTemp = new ArrayList();
                        headTemp.add(data.getTitle());
                        head.add(headTemp);
                    });

        }
        List dataList1 = new ArrayList();
        {

            // 处理每一行数据
            dataList.stream().forEach(data -> {
                List<Object> temp = new ArrayList<>();
                Map dataMap = (Map) data;
                // 根据key，处理每一个字段
                stringAmisListColumConfigDtoMap.keySet().stream().forEach(key -> {
                    // 获得AMIS配置
                    AmisListColumConfigDto amisListColumConfigDto = stringAmisListColumConfigDtoMap.get(key);

                    Object object = dataMap.get(key);
                    // 格式化date
                    if("date".equals(amisListColumConfigDto.getType())){
                        String format = amisListColumConfigDto.getFormat();
                        format = format.replaceAll("Y","y");
                        format = format.replaceAll("D","d");
                        format = format.replaceAll("hh","HH");

                        if(object instanceof Date){
                            object = DateUtils.parseDateToStr(format, (Date) object );
                        }else if(object instanceof Long){
                            object = DateUtils.parseDateToStr(format, new Date((Long) object) );
                        }else if(object instanceof Integer){
                            object = DateUtils.parseDateToStr(format, new Date((Integer) object) );
                        }
                    }

                    temp.add(object);
                });
                dataList1.add(temp);
            });
            dataList = null ;
        }

        ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
        byte[] byteExl = null ;
        try {

            WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
            WriteCellStyle headWriteCellStyle = new WriteCellStyle();
            // 标题字体大小
            WriteFont headWriteFont = new WriteFont();
            headWriteFont.setFontHeightInPoints((short) 11);
            headWriteFont.setFontName("宋体");
            headWriteCellStyle.setWriteFont(headWriteFont);
            headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
            //边框
            contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);
            contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);
            contentWriteCellStyle.setBorderRight(BorderStyle.THIN);
            contentWriteCellStyle.setBorderTop(BorderStyle.THIN);
            // 水平居中
            contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
            // 垂直居中
            contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
            // 设置自动换行，前提内容中需要加「\n」才有效
            contentWriteCellStyle.setWrapped(true);
            WriteFont contentWriteFont = new WriteFont();
            contentWriteFont.setFontHeightInPoints((short) 10);
            contentWriteFont.setFontName("宋体");
            contentWriteCellStyle.setWriteFont(contentWriteFont);

            //初始化样式
            HorizontalCellStyleStrategy horizontalCellStyleStrategy =
                    new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);


            ExcelWriter excelWriter = EasyExcel.write(arrayOutputStream)
                    .head(head)
                    .registerWriteHandler(horizontalCellStyleStrategy)
                    // 设置列宽
                    .registerWriteHandler(new ColumnHandler())
                    .build();

            WriteSheet writeSheet = EasyExcel
                    .writerSheet("Sheet1")
                    .build();


            excelWriter
                    .write(dataList1, writeSheet);

            excelWriter.finish();

            byteExl = arrayOutputStream.toByteArray();

        } finally {
            IoUtil.close(arrayOutputStream);
        }

        return byteExl ;
    }


    public class ColumnHandler extends AbstractColumnWidthStyleStrategy {

        @Override
        protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer integer, Boolean isHead) {
            boolean needSetWidth = isHead || !CollectionUtils.isEmpty(cellDataList);
            final int rowIndex = cell.getRowIndex();
            if (needSetWidth) {
                if (rowIndex == 0) {

                    Integer columnWidth = dataLength(cellDataList, cell, isHead);
                    if (columnWidth >= 0) {
                        if (columnWidth > 255) {
                            columnWidth = 255;
                        }
                        if(columnWidth < 16){
                            columnWidth = 16;
                        }
                        writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), columnWidth * 256);
                    }
                }
            }
        }
    }



    /**
     * 数据长度
     *
     * @param cellDataList
     * @param cell
     * @param isHead
     * @return
     */
    private Integer dataLength(List<WriteCellData<?>> cellDataList, Cell cell, Boolean isHead) {
        if (isHead) {
            return cell.getStringCellValue().getBytes().length;
        } else {
            CellData cellData = cellDataList.get(0);
            CellDataTypeEnum type = cellData.getType();
            if (type == null) {
                return -1;
            } else {
                switch (type) {
                    case STRING:
                        return cellData.getStringValue().getBytes().length + 10;
                    case BOOLEAN:
                        return cellData.getBooleanValue().toString().getBytes().length + 10;
                    case NUMBER:
                        return cellData.getNumberValue().toString().getBytes().length * 2 + 10;
                    default:
                        return -1;
                }
            }
        }
    }

}
